﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using ShadowCommando.Game.Utilites;
using ShadowCommando.Game.Elements.Enemies;
using ShadowCommando.Game.GameSounds;
namespace ShadowCommando.Game.Elements
{
    /// <summary>
    /// Podstawowa klasa po której dziedziczą wszystkie inne w grze
    /// </summary>
   public class Element:IComparable
    {
        #region Constructor
        /// <summary>
        /// Konstrutkor 
        /// </summary>
        /// <param name="_step">Krok</param>
        /// <param name="_diffculty">Poziom trudności</param>
        public Element(int _step,LevelDifficulty _diffculty)
        {
            step = _step;
            difficulty = _diffculty;
            switch (difficulty)
            {
                case LevelDifficulty.Padawan:
                    {
                        demageFactor = ElementInfo.Default.padawanDemageFactor;
                        atackFactor = ElementInfo.Default.padawanAtackFactor;
                        pointFactor = ElementInfo.Default.padawanPointsFactor;
                        break;
                    }
                case LevelDifficulty.Jedi:
                    {
                        demageFactor = ElementInfo.Default.jediDemageFactor;
                        atackFactor = ElementInfo.Default.jediAtackFactor;
                        pointFactor = ElementInfo.Default.jediPointsFactor;
                        break;
                    }
                case LevelDifficulty.JediMaster:
                    {
                        demageFactor = ElementInfo.Default.masterDemageFactor;
                        atackFactor = ElementInfo.Default.masterAtackFactor;
                        pointFactor = ElementInfo.Default.masterPointsFactor;
                        break;
                    }
                
            }
        }

        #endregion

        #region Items
       /// <summary>
       /// SoundId
       /// </summary>
       protected SoundID soundiD;
       /// <summary>
       /// Rodzaj elementu
       /// </summary>
       protected string kind;
       /// <summary>
       /// kolejność wyswietlania
       /// </summary>
       protected int zIndex;
        /// <summary>
        /// Droga do celu
        /// </summary>
       protected List<Point> path;
       /// <summary>
       /// ElementId
       /// </summary>
        protected ElementId elementId;
       /// <summary>
       /// Poziom trudności
       /// </summary>
        protected LevelDifficulty difficulty;
       /// <summary>
       /// Cosinus kąta
       /// </summary>
 
       protected double cos;
       /// <summary>
       /// Sinus kąta
       /// </summary>
        protected double sin;
       /// <summary>
       ///Max timer
       /// </summary>
        protected int timerCount;
       /// <summary>
       /// Aktualny timer
       /// </summary>
        protected int actualTimerCount;
       /// <summary>
       /// Priorytet rysowania
       /// </summary>
        protected int drawPriority;
       /// <summary>
       /// Kąt obrotu
       /// </summary>
        protected int? angle;
       /// <summary>
       /// Szerokość
       /// </summary>
        protected int width;
       /// <summary>
       /// Długość
       /// </summary>
        protected int height;
       /// <summary>
       /// Szerokość planszy dla algorytmu wyszukiwania ścieżki
       /// </summary>
        protected int boardWidth;
       /// <summary>
        /// 
        /// Wysokośc planszy dla algorytmu wyszukiwania ścieżki
       /// </summary>
        protected int boardHeight;
       /// <summary>
       /// Szerokość mapy
       /// </summary>
       protected int mapWidth;
       /// <summary>
       /// Wysokość mapy
       /// </summary>
       protected int mapHeight;
       /// <summary>
       /// Krok poruszania sie
       /// </summary>
        protected int step;
       /// <summary>
       /// Aktualny pancerz
       /// </summary>
        protected int armor;
      /// <summary>
      /// Aktualne życie
      /// </summary>
       protected int life;
       /// <summary>
       /// Licznik kroków
       /// </summary>
        protected int moveCount;
       /// <summary>
       /// Punkty
       /// </summary>
        protected int points;
       /// <summary>
       /// Pozostały czas
       /// </summary>
       protected int lefTime;
       /// <summary>
       /// Licznik animacji
       /// </summary>
        protected int animationCount;
       /// <summary>
       /// Punkty zdobyte
       /// </summary>
        protected int pts;
        

       /// <summary>
       /// Wskaźnik obrażenia
       /// </summary>
        protected double demageFactor;
       /// <summary>
       /// Wskaźnik punktów
       /// </summary>
        protected double pointFactor;
       /// <summary>
       /// Wskaźnik ataku
       /// </summary>
        protected double atackFactor;
       /// <summary>
       /// "Fake" pozycja
       /// </summary>
        protected Point fakeLocation;
       /// <summary>
       /// Pozycja na planszy do wyszukiwania ścieżki
       /// </summary>
       protected Point boardLocation;
       /// <summary>
       /// Pozycja na ekranie
       /// </summary>
        protected Point realLocation;

       /// <summary>
       /// Zniszczalny
       /// </summary>
        protected bool DestroyAble=true;
       /// <summary>
       /// Niesmiertelny
       /// </summary>
 
       protected bool immortal=false;
       /// <summary>
       /// Animowany
       /// </summary>
 
       protected bool isAnimated=false;
       /// <summary>
       /// Czy mozna po nim przechodzić
       /// </summary>
 
       protected bool movable=true;
       /// <summary>
       /// Czy mozna przez niego strzeląć
       /// </summary>
        protected bool shotable = false;
       /// <summary>
       /// Czy żyje
       /// </summary>
        protected bool isLive=true;
       /// <summary>
       /// Czy jest opancerzony
       /// </summary>
 
       protected bool isArmored=false;
       /// <summary>
       /// Czy reaguje
       /// </summary>
        private bool isAwake = false;
        #endregion


        #region Properties
       /// <summary>
       /// SoundId
       /// </summary>
       public SoundID SoundId
       {
           get { return soundiD; }
           set { soundiD = value; }
       }
       /// <summary>
       /// Rodzaj elementu
       /// </summary>
       public string Kind
       {
           get { return kind; }
        set { kind = value; }
       }
       /// <summary>
       /// Droga do celu
       /// </summary>
       public List<Point> Path
        {
            get { return path; }
            set { path = value; }
        }
       /// <summary>
       /// Id Elementu
       /// </summary>
        public ElementId ElementId
        {
         
            get { return elementId; }
            set { elementId = value; }
        }
        /// <summary>
        /// Kąt obrotu
        /// </summary>
        public int? Angle
        {
            get
            {
                return angle;
            }
            set
            {
                angle = value;
            }
        }
        /// <summary>
        /// Poziom trudności
        /// </summary>
        public LevelDifficulty Difficulty
        {
            get { return difficulty; }
            set { difficulty = value; }
        }
       /// <summary>
       /// Zdobyte punkty
       /// </summary>
        public int Pts
        {
            get { return pts; }
            set { pts = value; }
        }
       /// <summary>
       /// Szerokość elementu
       /// </summary>
        public int Width
        {
            get
            {
                return width;
            }
            set
            {
                width = value;
            }
        }
       /// <summary>
       /// Wysokość elementu
       /// </summary>
        public int Height
        {
            get
            {
                return height;
            }
            set
            {
                height = value;
            }
        }
        /// <summary>
        /// Szerokość planszy dla algorytmu wyszukiwania ścieżki
        /// </summary>
        public int BoardWidth
        {
            get
            {
                return boardWidth;
            }
            set
            {
                boardWidth = value;
            }
        }
       /// <summary>
        /// Wysokośc planszy dla algorytmu wyszukiwania ścieżki
       /// </summary>
        public int BoardHeight
        {
            get
            {
                return boardHeight;
            }
            set
            {
                boardHeight = value;
            }
        }
        /// <summary>
        /// "Fejkowy " lewy róg 
        /// </summary>
        public int FakeX
        {
            get
            {
                return fakeLocation.X;
            }
            set
            {
                
                    fakeLocation.X = value;

            }
        }
       /// <summary>
       /// "Fejkowy" górny róg
       /// </summary>
        public int FakeY
        {
            get
            {
                return fakeLocation.Y;
            }
            set
            {
                
                    fakeLocation.Y = value;
            }
        }
       /// <summary>
        /// Lewy róg na planszy do algorytmu wyszukiwania najkrótszej ścieżki
       /// </summary>
        public int BoardX
        {
            get
            {
                return boardLocation.X;
            }
            set
            {
                boardLocation.X = value;
            }
        }
       /// <summary>
       /// Górny róg na planszy do algorytmu wyszukiwania najkrótszej ścieżki
       /// </summary>
        public int BoardY
        {
            get
            {
                return boardLocation.Y;
            }
            set
            {
                boardLocation.Y = value;
            }
        }
       /// <summary>
       /// Lewy róg na ekranie
       /// </summary>
        public int RealX
        {
            get
            {
                return realLocation.X;
            }
            set
            {
                realLocation.X = value;
            }
        }
       /// <summary>
       /// Górny róg na ekranie
       /// </summary>
        public int RealY
        {
            get
            {
                return realLocation.Y;
            }
            set
            {
                realLocation.Y = value;
            }
        }
       /// <summary>
       /// Krok
       /// </summary>
        public int Step
        {
            get
            {
                return step;
            }
            set
            {
                step = value;
            }
        }
       /// <summary>
       /// Aktualny pancerz
       /// </summary>
        public int Armor
        {
            get
            {
                return armor;
            }
            set
            {
                armor = value;
            }
        }
       /// <summary>
       /// Aktualne życie
       /// </summary>
        public int Life
        {
            get
            {
                return life;
            }
            set
            {
               life= value;
            }
        }
       /// <summary>
       /// Punkty
       /// </summary>
        public int Points
        {
            get
            {
                return (int)(pointFactor*  points);
            }
            set { points = value; }
        }
       /// <summary>
       /// Pozostały czas
       /// </summary>
        public int LeftTime
        {
            get
            {
                return lefTime;
            }
            set
            {
                lefTime = value;
            }
        }

       /// <summary>
       /// Licznik animacji
       /// </summary>
        public int AnimationCount
        {
            get
            {
                return animationCount;
            }
            set
            {
                animationCount = value;
            }
        }
       /// <summary>
       /// Priorytet rysowania
       /// </summary>
        public int DrawPriority
        {
            get
            {
                return drawPriority;
            }
            set
            {
                drawPriority = value;
            }
        }
       /// <summary>
       /// Maxymalna wartość licznika czasu
       /// </summary>
        public int TimerCount
        {
            get { return timerCount; }
            set { timerCount = value; }

        }
       /// <summary>
       /// Aktualny stan licznika czasu
       /// </summary>
        public int ActualTimerCount
        {
            get { return actualTimerCount; }
            set { actualTimerCount = value; }
        }
       /// <summary>
       /// Licznik ruchu
       /// </summary>
        public int MoveCount
        {
            get { return moveCount; }
            set { moveCount = value; }
        }
       /// <summary>
       /// Zindex
       /// </summary>
       public int ZIndex
       {
           get { return zIndex; }
           set { zIndex = value;  }
       }
       /// <summary>
       /// Sinus kąta obrotu
       /// </summary>
        public double Sin
        {
            get
            {
                return sin;
            }
            set
            {
                sin = value;
            }
        }
       /// <summary>
       /// Czy jest obudzony
       /// </summary>
        public bool IsAwake
        {
            get { return isAwake; }
            set { isAwake = value; }
        }
       /// <summary>
       /// Czy nieśmiertelny
       /// </summary>
        public bool Immortal
        {
            get { return immortal; }
            set { immortal = value; }
        }
       /// <summary>
       /// Czy żyje
       /// </summary>
        public bool IsLive
        {
            get
            {
                return isLive;
            }
            set
            {
                isLive = value;
            }
        }
       /// <summary>
       ///Czy jest opancerzony
       /// </summary>
        public bool IsArmored
        {
            get
            {
                return isArmored;
            }
            set
            {
                isArmored = value;
            }
        }
       /// <summary>
       /// "Fake" pozycja
       /// </summary>
        public Point FakeLocation
        {
            get
            {
                return fakeLocation;
            }
            set
            {
                fakeLocation = value;
            }
        }
       /// <summary>
       /// Pozycja na planszy do wyszukiwania najkrótszej ścieżki
       /// </summary>
        public Point BoardLocation
        {
            get
            {
                return boardLocation;
            }
            set
            {
                boardLocation = value;
            }
        }
       /// <summary>
       /// Pozycja na ekranie
       /// </summary>
        public Point RealLocation
        {
            get
            {
                return realLocation;
            }
            set
            {
                realLocation = value;
            }
        }
       /// <summary>
       /// Czy można przez element przechodzić
       /// </summary>
        public bool Movable
        {
            get
            {
                return movable;
            }
            set
            {
                movable = value;
            }
        }
       /// <summary>
       /// Czy przechodzą przez element kule
       /// </summary>
        public bool Shootable
        {
            get
            {
                return shotable;
            }
            set
            {
                shotable = value;
            }
        }
       /// <summary>
       /// Czy jest animowany
       /// </summary>
        public bool IsAnimated
        {
            get
            {
                return isAnimated;
            }
            set
            {
                isAnimated = value;
            }
        }

        #endregion

        #region Functions
        /// <summary>
        /// Czy inny element znajduje się w środku innego elementu 
        /// </summary>
        /// <param name="el">Element sprawdzany</param>
        /// <returns>True Znajduje sie False Nie znajduje się</returns>
        public bool InsideElement(Element el)
        {
            return InsideElement(el.FakeX + el.Width/2, el.FakeY + el.Height/2);
        }
        /// <summary>
        /// Czy inny element znajduje się w środku innego elementu
        /// </summary>
        /// <param name="x">Lewy róg</param>
        /// <param name="y">Górny róg</param>
        /// <returns>True Znajduje sie False Nie znajduje się</returns>
        public bool InsideElement(int x, int y)
        {
            if (FakeX <= x && FakeY <= y && FakeX <= x && FakeY + Height >= y && FakeX + Width >= x && FakeY <= y && FakeX + Width >= x && FakeY + Height >= y)
                return true;
            return false;
        }
       /// <summary>
       /// Oblicza obrót elementu
       /// </summary>
       /// <param name="p1">Punkt w którego strone ma obrócić się element
       /// </param>
        public void CalculateRotation(Point p1)
        {
            int cwiart = 0;
            int wsp = 1;
            int x1 = RealX + Width / 2;
            int y1 = RealY + Height / 2;

            int x2 = p1.X;
            int y2 = y1;

            int dx1 = p1.X;
            int dy2 = p1.Y;

            double a1 = y1 - y2;
            double a2 = dy2 - y1;

            double b1 = x2 - x1;
            double b2 = x1 - dx1;

            cos = (a1 * a2 + b1 * b2) / (Math.Sqrt(a1 * a1 + b1 * b1) * Math.Sqrt(a2 * a2 + b2 * b2));

            sin = (a1 * b2 - a2 * b1) / (Math.Sqrt(a1 * a1 + b1 * b1) * Math.Sqrt(a2 * a2 + b2 * b2));
            if ((a1 == 0 && b1 == 0) || (a2 == 0 && b2 == 0))
                sin = 0;
            if ((a1 == 0 && b1 == 0) || (a2 == 0 && b2 == 0))
                cos = 0;
            if (dx1 > x1 && dy2 < y1)
                cwiart = -180;
            else if (dx1 < x1 && dy2 < y1)
                wsp = -1;
            else if (dx1 > x1 && dy2 > y1)
            {
                wsp = -1;
                cwiart = 180;
            }

            angle = (int)((Math.Acos(cos) * 180) / Math.PI) * wsp + cwiart;
        }
       /// <summary>
       /// Ustaw rozmiary
       /// </summary>
       /// <param name="_width">Szerokość</param>
       /// <param name="_height">Wysokość</param>
        public void SetSize(int _width, int _height)
        {
            width = _width;
            height = _height;
        }
       /// <summary>
       /// Element otrzymuje obrażęnia
       /// </summary>
       /// <param name="demage">Wielkość obrażeń</param>
       /// <returns>Czy element został zniszczony</returns>
        public bool GetDemage(int demage)
        {
            
            if (immortal)
                return true;
              if (isLive)
            {
                armor = armor - demage;
                if (armor <= 0)
                {
                    life = life + armor;
                    armor = 0;
                    isArmored = false;
                    if (life <= 0)
                        isLive = false;
                }
            }
            return isLive;
        }
        #endregion
        
        /// <summary>
        /// Implementacja interfejsu Comperable
        /// </summary>
        /// <param name="obj">Porównywany obiekt</param>
        /// <returns></returns>
        public int CompareTo(object obj)
        {
            Element element = obj as Element;
            if (zIndex > element.ZIndex)
                return 1;
            else if (zIndex < element.ZIndex)
                return -1;
            else
                return 0;
        }
    }
}
